#include "dominion.h"
#include "dominion_helpers.h"
#include "rngs.h"
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <stdbool.h>

int compare(const void *a, const void *b)
{
    if (*(int *) a > *(int *) b)
        return 1;
    if (*(int *) a < *(int *) b)
        return -1;
    return 0;
}

struct gameState *newGame()
{
    struct gameState *g = malloc(sizeof(struct gameState));
    return g;
}

int *kingdomCards(int k1, int k2, int k3, int k4, int k5, int k6, int k7,
                  int k8, int k9, int k10)
{
    int *k = malloc(10 * sizeof(int));
    k[0] = k1;
    k[1] = k2;
    k[2] = k3;
    k[3] = k4;
    k[4] = k5;
    k[5] = k6;
    k[6] = k7;
    k[7] = k8;
    k[8] = k9;
    k[9] = k10;
    return k;
}

int initializeGame(int numPlayers, int kingdomCards[10], int randomSeed,
                   struct gameState *state)
{

    int i;
    int j;
    int it;
    //set up random number generator
    SelectStream(1);
    PutSeed((long) randomSeed);

    //check number of players
    if (numPlayers > MAX_PLAYERS || numPlayers < 2)
    {
        return -1;
    }
    //set number of players
    state->numPlayers = numPlayers;

    //check selected kingdom cards are different
    for (i = 0; i < 10; i++)
    {
        for (j = 0; j < 10; j++)
        {
            if (j != i && kingdomCards[j] == kingdomCards[i])
            {
                return -1;
            }
        }
    }


    //initialize supply
    ///////////////////////////////

    //set number of Curse cards
    if (numPlayers == 2)
    {
        state->supplyCount[curse] = 10;
    }
    else if (numPlayers == 3)
    {
        state->supplyCount[curse] = 20;
    }
    else
    {
        state->supplyCount[curse] = 30;
    }

    //set number of Victory cards
    if (numPlayers == 2)
    {
        state->supplyCount[estate] = 8;
        state->supplyCount[duchy] = 8;
        state->supplyCount[province] = 8;
    }
    else
    {
        state->supplyCount[estate] = 12;
        state->supplyCount[duchy] = 12;
        state->supplyCount[province] = 12;
    }

    //set number of Treasure cards
    state->supplyCount[copper] = 60 - (7 * numPlayers);
    state->supplyCount[silver] = 40;
    state->supplyCount[gold] = 30;

    //set number of Kingdom cards
    for (i = adventurer; i <= treasure_map; i++)        //loop all cards
    {
        for (j = 0; j < 10; j++)        //loop chosen cards
        {
            if (kingdomCards[j] == i)
            {
                //check if card is a 'Victory' Kingdom card
                if (kingdomCards[j] == great_hall
                    || kingdomCards[j] == gardens)
                {
                    if (numPlayers == 2)
                    {
                        state->supplyCount[i] = 8;
                    }
                    else
                    {
                        state->supplyCount[i] = 12;
                    }
                }
                else
                {
                    state->supplyCount[i] = 10;
                }
                break;
            }
            else                //card is not in the set choosen for the game
            {
                state->supplyCount[i] = -1;
            }
        }

    }

    ////////////////////////
    //supply intilization complete

    //set player decks
    for (i = 0; i < numPlayers; i++)
    {
        state->deckCount[i] = 0;
        for (j = 0; j < 3; j++)
        {
            state->deck[i][j] = estate;
            state->deckCount[i]++;
        }
        for (j = 3; j < 10; j++)
        {
            state->deck[i][j] = copper;
            state->deckCount[i]++;
        }
    }

    //shuffle player decks
    for (i = 0; i < numPlayers; i++)
    {
        if (shuffle(i, state) < 0)
        {
            return -1;
        }
    }

    //set embargo tokens to 0 for all supply piles
    for (i = 0; i <= treasure_map; i++)
    {
        state->embargoTokens[i] = 0;
    }

    //initialize first player's turn
    state->outpostPlayed = 0;
    state->phase = 0;
    state->numActions = 1;
    state->numBuys = 1;
    state->playedCardCount = 0;
    state->whoseTurn = 0;
    state->handCount[state->whoseTurn] = 0;

    //draw player hands
    for (i = 0; i < numPlayers; i++)
    {
        state->handCount[i] = 0;
        state->discardCount[i] = 0;
        for (it = 0; it < 5; it++)
            drawCard (i, state);
    }

    state->coinBonus = 0;
    updateCoins(state->whoseTurn, state, state->coinBonus);

    return 0;
}

int shuffle(int player, struct gameState *state)
{


    int newDeck[MAX_DECK];
    int newDeckPos = 0;
    int card;
    int i;

    if (state->deckCount[player] < 1)
        return -1;
    qsort((void *) (state->deck[player]), state->deckCount[player],
          sizeof(int), compare);
    /* SORT CARDS IN DECK TO ENSURE DETERMINISM! */

    while (state->deckCount[player] > 0)
    {
        card = floor(Random() * state->deckCount[player]);
        newDeck[newDeckPos] = state->deck[player][card];
        newDeckPos++;
        for (i = card; i < state->deckCount[player] - 1; i++)
        {
            state->deck[player][i] = state->deck[player][i + 1];
        }
        state->deckCount[player]--;
    }
    for (i = 0; i < newDeckPos; i++)
    {
        state->deck[player][i] = newDeck[i];
        state->deckCount[player]++;
    }

    return 0;
}

int playCard(int handPos, int choice1, int choice2, int choice3,
             struct gameState *state)
{
    int card;

    //check if it is the right phase
    if (state->phase != 0)
    {
        return -1;
    }
    //check if player has enough actions
    if (state->numActions < 1)
    {
        return -1;
    }
    //get card played
    card = handCard(handPos, state);

    //check if selected card is an action
    if (card < adventurer || card > treasure_map)
    {
        return -1;
    }
    
    //play card
    if (cardEffect
        (card, choice1, choice2, choice3, state, handPos, &state->coinBonus) < 0)
    {
        return -1;
    }
    //reduce number of actions
    state->numActions--;

    //update coins (Treasure cards may be added with card draws)
    updateCoins(state->whoseTurn, state, state->coinBonus);

    return 0;
}

int buyCard(int supplyPos, struct gameState *state)
{
    int who;
    
    dprintf ("Entering buyCard...\n");
    // I don't know what to do about the phase thing.

    who = state->whoseTurn;

    if (state->numBuys < 1)
    {
        dprintf ("You do not have any buys left\n");
        return -1;
    }
    else if (supplyCount(supplyPos, state) < 1)
    {
        dprintf ("There are not any of that type of card left\n");
        return -1;
    }
    else if (state->coins < getCost(supplyPos))
    {
        dprintf
            ("You do not have enough money to buy that. You have %d coins.\n",
             state->coins);
        return -1;
    }
    else
    {
        state->phase = 1;
        //state->supplyCount[supplyPos]--;
        gainCard(supplyPos, state, 0, who);     //card goes in discard, this might be wrong.. (2 means goes into hand, 0 goes into discard)

        state->coins = (state->coins) - (getCost(supplyPos));
        state->numBuys--;
        dprintf
            ("You bought card number %d for %d coins. You now have %d buys and %d coins.\n",
             supplyPos, getCost(supplyPos), state->numBuys, state->coins);
    }

    //state->discard[who][state->discardCount[who]] = supplyPos;
    //state->discardCount[who]++;

    return 0;
}

int numHandCards(struct gameState *state)
{
    return state->handCount[whoseTurn(state)];
}

int handCard(int handPos, struct gameState *state)
{
    int currentPlayer = whoseTurn(state);
    return state->hand[currentPlayer][handPos];
}

int supplyCount(int card, struct gameState *state)
{
    return state->supplyCount[card];
}

int fullDeckCount(int player, int card, struct gameState *state)
{
    int i;
    int count = 0;

    for (i = 0; i < state->deckCount[player]; i++)
    {
        if (state->deck[player][i] == card)
            count++;
    }

    for (i = 0; i < state->handCount[player]; i++)
    {
        if (state->hand[player][i] == card)
            count++;
    }

    for (i = 0; i < state->discardCount[player]; i++)
    {
        if (state->discard[player][i] == card)
            count++;
    }

    return count;
}

int whoseTurn(struct gameState *state)
{
    return state->whoseTurn;
}

int endTurn(struct gameState *state)
{
    int k;
    int i;
    int currentPlayer = whoseTurn(state);

    //Discard hand
    for (i = 0; i < state->playedCardCount; i++)
    {
        state->discard[currentPlayer][state->discardCount[currentPlayer]++] = state->playedCards[i];    //Discard
        state->playedCards[i] = -1;     //Set card to -1
    }
    for (i = 0; i < state->handCount[currentPlayer]; i++)
    {
        state->discard[currentPlayer][state->discardCount[currentPlayer]++] = state->hand[currentPlayer][i];    //Discard
        state->hand[currentPlayer][i] = -1;     //Set card to -1
    }
    state->handCount[currentPlayer] = 0;        //Reset hand count
    
    // Draw next hand
    for (k = 0; k < 5; k++)
        drawCard(state->whoseTurn, state);

    //Code for determining the player
    if (currentPlayer < (state->numPlayers - 1))
    {
        state->whoseTurn = currentPlayer + 1;   //Still safe to increment
    }
    else
    {
        state->whoseTurn = 0;   //Max player has been reached, loop back around to player 1
    }

    state->outpostPlayed = 0;
    state->phase = 0;
    state->numActions = 1;
    state->coinBonus = 0;
    state->coins = 0;
    state->numBuys = 1;
    state->playedCardCount = 0;

    //Update money
    updateCoins(state->whoseTurn, state, state->coinBonus);

    return 0;
}

int isGameOver(struct gameState *state)
{
    int i;
    int j;

    //if stack of Province cards is empty, the game ends
    if (state->supplyCount[province] == 0)
    {
        return 1;
    }
    //if three supply pile are at 0, the game ends
    j = 0;
    for (i = 0; i < 25; i++)
    {
        if (state->supplyCount[i] == 0)
        {
            j++;
        }
    }
    if (j >= 3)
    {
        return 1;
    }

    return 0;
}

int scoreFor(int player, struct gameState *state)
{

    int i;
    int score = 0;
    //score from hand
    for (i = 0; i < state->handCount[player]; i++)
    {
        if (state->hand[player][i] == curse)
        {
            score = score - 1;
        };
        if (state->hand[player][i] == estate)
        {
            score = score + 1;
        };
        if (state->hand[player][i] == duchy)
        {
            score = score + 3;
        };
        if (state->hand[player][i] == province)
        {
            score = score + 6;
        };
        if (state->hand[player][i] == great_hall)
        {
            score = score + 1;
        };
        if (state->hand[player][i] == gardens)
        {
            score = score + (fullDeckCount(player, 0, state) / 10);
        };
    }

    //score from discard
    for (i = 0; i < state->discardCount[player]; i++)
    {
        if (state->discard[player][i] == curse)
        {
            score = score - 1;
        };
        if (state->discard[player][i] == estate)
        {
            score = score + 1;
        };
        if (state->discard[player][i] == duchy)
        {
            score = score + 3;
        };
        if (state->discard[player][i] == province)
        {
            score = score + 6;
        };
        if (state->discard[player][i] == great_hall)
        {
            score = score + 1;
        };
        if (state->discard[player][i] == gardens)
        {
            score = score + (fullDeckCount(player, 0, state) / 10);
        };
    }

    //score from deck
    for (i = 0; i < state->discardCount[player]; i++)
    {
        if (state->deck[player][i] == curse)
        {
            score = score - 1;
        };
        if (state->deck[player][i] == estate)
        {
            score = score + 1;
        };
        if (state->deck[player][i] == duchy)
        {
            score = score + 3;
        };
        if (state->deck[player][i] == province)
        {
            score = score + 6;
        };
        if (state->deck[player][i] == great_hall)
        {
            score = score + 1;
        };
        if (state->deck[player][i] == gardens)
        {
            score = score + (fullDeckCount(player, 0, state) / 10);
        };
    }

    return score;
}

int getWinners(int players[MAX_PLAYERS], struct gameState *state)
{
    int i;
    int j;
    int highScore;
    int currentPlayer;

    //get score for each player
    for (i = 0; i < MAX_PLAYERS; i++)
    {
        //set unused player scores to -9999
        if (i >= state->numPlayers)
        {
            players[i] = -9999;
        }
        else
        {
            players[i] = scoreFor(i, state);
        }
    }

    //find highest score
    j = 0;
    for (i = 0; i < MAX_PLAYERS; i++)
    {
        if (players[i] > players[j])
        {
            j = i;
        }
    }
    highScore = players[j];

    //add 1 to players who had less turns
    currentPlayer = whoseTurn(state);
    for (i = 0; i < MAX_PLAYERS; i++)
    {
        if (players[i] == highScore && i > currentPlayer)
        {
            players[i]++;
        }
    }

    //find new highest score
    j = 0;
    for (i = 0; i < MAX_PLAYERS; i++)
    {
        if (players[i] > players[j])
        {
            j = i;
        }
    }
    highScore = players[j];

    //set winners in array to 1 and rest to 0
    for (i = 0; i < MAX_PLAYERS; i++)
    {
        if (players[i] == highScore)
        {
            players[i] = 1;
        }
        else
        {
            players[i] = 0;
        }
    }

    return 0;
}

int drawCard(int player, struct gameState *state)
{
    int count;
    int deckCounter;
    if (state->deckCount[player] <= 0)
    {                           //Deck is empty

        //Step 1 Shuffle the discard pile back into a deck
        int i;
        //Move discard to deck
        for (i = 0; i < state->discardCount[player]; i++)
        {
            state->deck[player][i] = state->discard[player][i];
            state->discard[player][i] = -1;
        }

        state->deckCount[player] = state->discardCount[player];
        state->discardCount[player] = 0;        //Reset discard

        //Shufffle the deck
        shuffle(player, state); //Shuffle the deck up and make it so that we can draw

        dprintf ("Deck count now: %d\n", state->deckCount[player]);

        state->discardCount[player] = 0;

        //Step 2 Draw Card
        count = state->handCount[player];       //Get current player's hand count

        dprintf ("Current hand count: %d\n", count);

        deckCounter = state->deckCount[player]; //Create a holder for the deck count

        if (deckCounter == 0)
            return -1;

        state->hand[player][count] = state->deck[player][deckCounter - 1];      //Add card to hand
        state->deckCount[player]--;
        state->handCount[player]++;     //Increment hand count
    }

    else
    {
        int count = state->handCount[player];   //Get current hand count for player
        int deckCounter;
        
        dprintf ("Current hand count: %d\n", count);

        deckCounter = state->deckCount[player]; //Create holder for the deck count
        state->hand[player][count] = state->deck[player][deckCounter - 1];      //Add card to the hand
        state->deckCount[player]--;
        state->handCount[player]++;     //Increment hand count
    }

    return 0;
}

int getCost(int cardNumber)
{
    switch (cardNumber)
    {
    case curse:
        return 0;
    case estate:
        return 2;
    case duchy:
        return 5;
    case province:
        return 8;
    case copper:
        return 0;
    case silver:
        return 3;
    case gold:
        return 6;
    case adventurer:
        return 6;
    case council_room:
        return 5;
    case feast:
        return 4;
    case gardens:
        return 4;
    case mine:
        return 5;
    case remodel:
        return 4;
    case smithy:
        return 4;
    case village:
        return 3;
    case baron:
        return 4;
    case great_hall:
        return 3;
    case minion:
        return 5;
    case steward:
        return 3;
    case tribute:
        return 5;
    case ambassador:
        return 3;
    case cutpurse:
        return 4;
    case embargo:
        return 2;
    case outpost:
        return 5;
    case salvager:
        return 4;
    case sea_hag:
        return 4;
    case treasure_map:
        return 4;
    }

    return -1;
}

// Discard the first instance of the specified card type from the player's
// hand. Needed in some cases to discard action cards after they've been
// played, because the card may have the effect of rearranging the player's
// hand, making the value of handPos supplied to cardEffect no longer valid.
static int discardCardType (    int cardType, int currentPlayer, 
                                struct gameState *state, int trashFlag )
{
    int i;
    
    for (i = 0; i < state->handCount[currentPlayer]; i++)
    {
        if (state->hand[currentPlayer][i] == cardType)
            return discardCard (i, currentPlayer, state, trashFlag);
    }
    
    // No card of the appropriate type was found in the player's hand.
    return -1;
}

static int adventurer_effect (struct gameState *state, int currentPlayer)
{
    int drawntreasure = 0;
    
    while (drawntreasure < 2)
    {
        int drawn_card_pos = state->handCount[currentPlayer];
        drawCard (currentPlayer, state);
        int card = state->hand[currentPlayer][drawn_card_pos];
        
        if (card >= copper && card <= gold)
        {
            drawntreasure++;
        }
        else
        {
            // Discard non-treasure cards
            state->discard[currentPlayer][state->discardCount[currentPlayer]++] = 
                state->hand[currentPlayer][--state->handCount[currentPlayer]];
        }
    }
    
    //put played card in played card pile
    discardCardType (adventurer, currentPlayer, state, 0);
    
    return 0;
}

static int council_room_effect (struct gameState *state, int currentPlayer,
                                int handPos)
{
    int i;
    
    //+4 Cards
    for (i = 0; i < 4; i++)
        drawCard(currentPlayer, state);

    //+1 Buy
    state->numBuys++;

    //Each other player draws a card
    for (i = 0; i < state->numPlayers; i++)
    {
        if (i != currentPlayer)
            drawCard(i, state);
    }

    //put played card in played card pile
    discardCard(handPos, currentPlayer, state, 0);

    return 0;
}

static int feast_effect (struct gameState *state, int currentPlayer, 
                         int choice1, int handPos)
{
    bool success = false;
    
    // If the card we want to gain costs more than 5, this is an invalid move.
    if (getCost (choice1) > 5)
        return -1; 
    
    // If gainCard returns an error code (for example, if there are no more
    // such cards in the supply,) this is an invalid move.
    if (gainCard (choice1, state, 0, currentPlayer) < 0)
        return -1;
    
    //trash the used feast
    discardCard(handPos, currentPlayer, state, 1);
    
    return 0;
}

int mine_effect (struct gameState *state, int currentPlayer, int handPos,
                 int choice1, int choice2)
{
    int i, j;
    
    j = state->hand[currentPlayer][choice1];        //store card we will trash

    if (state->hand[currentPlayer][choice1] < copper
        || state->hand[currentPlayer][choice1] > gold)
    {
        return -1;
    }

    if (choice2 < copper || choice2 > gold)
    {
        return -1;
    }

    if ((getCost(state->hand[currentPlayer][choice1]) + 3) <
        getCost(choice2))
    {
        return -1;
    }

    gainCard(choice2, state, 2, currentPlayer);

    //discard card from hand
    discardCard(handPos, currentPlayer, state, 0);

    // skip through player's hand until we find the card we'll trash
    i = 0;
    while (i < state->handCount[currentPlayer] && state->hand[currentPlayer][i] != j)
        i++;
    
    // discard trashed card
    discardCard (i, currentPlayer, state, 1);

    return 0;
}

int remodel_effect (struct gameState *state, int currentPlayer, int handPos,
                    int choice1, int choice2)
{
    int i, j;
    
    j = state->hand[currentPlayer][choice1];        //store card we will trash

    if ((getCost(state->hand[currentPlayer][choice1]) + 2) <
        getCost(choice2))
    {
        return -1;
    }

    gainCard(choice2, state, 0, currentPlayer);

    //discard card from hand
    discardCard(handPos, currentPlayer, state, 0);

    // skip through player's hand until we find the card we'll trash
    i = 0;
    while (i < state->handCount[currentPlayer] && state->hand[currentPlayer][i] != j)
        i++;
    
    // discard trashed card
    discardCard (i, currentPlayer, state, 1);

    return 0;
}

int baron_effect (  struct gameState *state, int currentPlayer, int choice1,
                    int *bonus )
{
    state->numBuys++;       //Increase buys by 1!
    if (choice1 > 0 && discardCardType (estate, currentPlayer, state, 0) >= 0)
    {
        // If an estate card was successfully discarded, move it from the
        // played card pile to the actual discard pile.
        int new_discardcount = state->discardCount[currentPlayer]++;
        state->discard[currentPlayer][new_discardcount] = 
            state->playedCards[--state->playedCardCount];
        *bonus += 4;  //Add 4 coins to the amount of coins
    }
    else
    {
        if (choice1 > 0)
        {
            dprintf ("No estate cards in your hand, invalid choice\n");
            dprintf ("Must gain an estate if there are any\n");
        }
        
        if (supplyCount(estate, state) > 0)
        {
            gainCard(estate, state, 0, currentPlayer);      //Gain an estate
            state->supplyCount[estate]--;   //Decrement Estates
            if (supplyCount(estate, state) == 0)
            {
                isGameOver(state);
            }
        }
    }
    
    //discard played card from hand
    return discardCardType (baron, currentPlayer, state, 0);
}

int minion_effect ( struct gameState *state, int currentPlayer, int handPos,
                    int choice1, int choice2, int *bonus )
{
    int i, j;
    
    //+1 action
    state->numActions++;

    //discard card from hand
    discardCard(handPos, currentPlayer, state, 0);

    if (choice1)            //+2 coins
    {
        *bonus += 2;
    }
    else if (choice2)       //discard hand, redraw 4, other players with 5+ cards discard hand and draw 4
    {
        //discard hand
        while (numHandCards(state) > 0)
        {
            discardCard (0, currentPlayer, state, 0);
        }

        //draw 4
        for (i = 0; i < 4; i++)
        {
            drawCard (currentPlayer, state);
        }

        //other players discard hand and redraw if hand size > 4
        for (i = 0; i < state->numPlayers; i++)
        {
            if (i != currentPlayer)
            {
                if (state->handCount[i] > 4)
                {
                    //discard hand
                    while (state->handCount[i] > 0)
                    {
                        discardCard (0, i, state, 0);
                    }

                    //draw 4
                    for (j = 0; j < 4; j++)
                    {
                        drawCard (i, state);
                    }
                }
            }
        }

    }
    return 0;
}

int salvager_effect (   struct gameState *state, int currentPlayer,
                        int choice1, int *bonus )
{
     if (choice1 < 0 || choice1 >= state->handCount[currentPlayer])
            return -1;
    
    //+1 buy
    state->numBuys++;

    //gain coins equal to trashed card
    *bonus += getCost(handCard(choice1, state));
    //trash card
    discardCard (choice1, currentPlayer, state, 1);
    
    //discard played card
    return discardCardType (salvager, currentPlayer, state, 0);
}

int sea_hag_effect (struct gameState *state, int currentPlayer)
{
    for (int i = 0; i < state->numPlayers; i++)
    {
        if (i != currentPlayer)
        {
            // Use drawCard to get the top card from the ith player's deck
            // in case a shuffle is needed.
            if (drawCard (i, state) == -1)
                return -1;
            state->discard[i][state->discardCount[i]++] =
                state->hand[i][--state->handCount[i]];
            state->deck[i][state->deckCount[i]++] = curse;  //Top card now a curse
        }
    }
    
    //discard played card
    return discardCardType (sea_hag, currentPlayer, state, 0);
}

// cardEffect still takes a bonus argument instead of looking in state->bonus
// because we want to maintain compatiblity with other test suites that other
// people may have written, and that means not changing the number of
// arguments or what they do.
int cardEffect (int card, int choice1, int choice2, int choice3,
                struct gameState *state, int handPos, int *bonus)
{
    int i;
    int j;
    int k;
    int index;
    int currentPlayer = whoseTurn(state);
    int nextPlayer = currentPlayer + 1;

    int tributeRevealedCards[2] = { -1, -1 };
    
    if (nextPlayer > (state->numPlayers - 1))
        nextPlayer = 0;
    
    //uses switch to select card and perform actions
    switch (card)
    {
    case adventurer:
        return adventurer_effect (state, currentPlayer);

    case council_room:
        return council_room_effect (state, currentPlayer, handPos);

    case feast:
        return feast_effect (state, currentPlayer, choice1, handPos);

    case gardens:
        return -1;

    case mine:
        return mine_effect (state, currentPlayer, handPos, choice1, choice2);

    case remodel:
        return remodel_effect (state, currentPlayer, handPos, choice1, choice2);

    case smithy:
        //+3 Cards
        for (i = 0; i < 3; i++)
        {
            drawCard(currentPlayer, state);
        }

        //discard card from hand
        discardCard(handPos, currentPlayer, state, 0);
        return 0;

    case village:
        //+1 Card
        drawCard(currentPlayer, state);

        //+2 Actions
        state->numActions = state->numActions + 2;

        //discard played card from hand
        discardCard(handPos, currentPlayer, state, 0);
        return 0;

    case baron:
        return baron_effect (state, currentPlayer, choice1, bonus);

    case great_hall:
        //+1 Card
        drawCard(currentPlayer, state);

        //+1 Actions
        state->numActions++;

        //discard card from hand
        discardCard(handPos, currentPlayer, state, 0);
        return 0;

    case minion:
        return minion_effect (state, currentPlayer, handPos, choice1, choice2, bonus);

    case steward:
        if (choice1 == 1)
        {
            //+2 cards
            drawCard(currentPlayer, state);
            drawCard(currentPlayer, state);
        }
        else if (choice1 == 2)
        {
            //+2 coins
            *bonus += 2;
        }
        else
        {
            //trash 2 cards in hand
            discardCard(choice2, currentPlayer, state, 1);
            discardCard(choice3, currentPlayer, state, 1);
        }

        //discard card from hand
        discardCard(handPos, currentPlayer, state, 0);
        return 0;

    case tribute:
        if ((state->discardCount[nextPlayer] +
             state->deckCount[nextPlayer]) <= 1)
        {
            if (state->deckCount[nextPlayer] > 0)
            {
                tributeRevealedCards[0] =
                    state->deck[nextPlayer][state->deckCount[nextPlayer] -
                                            1];
                state->deckCount[nextPlayer]--;
            }
            else if (state->discardCount[nextPlayer] > 0)
            {
                tributeRevealedCards[0] =
                    state->
                    discard[nextPlayer][state->discardCount[nextPlayer] -
                                        1];
                state->discardCount[nextPlayer]--;
            }
            else
            {
                //No Card to Reveal
                dprintf ("No cards to reveal\n");
            }
        }

        else
        {
            if (state->deckCount[nextPlayer] == 0)
            {
                for (i = 0; i < state->discardCount[nextPlayer]; i++)
                {
                    state->deck[nextPlayer][i] = state->discard[nextPlayer][i]; //Move to deck
                    state->deckCount[nextPlayer]++;
                    state->discard[nextPlayer][i] = -1;
                    state->discardCount[nextPlayer]--;
                }

                shuffle(nextPlayer, state);     //Shuffle the deck
            }
            tributeRevealedCards[0] =
                state->deck[nextPlayer][state->deckCount[nextPlayer] - 1];
            state->deck[nextPlayer][state->deckCount[nextPlayer]--] = -1;
            state->deckCount[nextPlayer]--;
            tributeRevealedCards[1] =
                state->deck[nextPlayer][state->deckCount[nextPlayer] - 1];
            state->deck[nextPlayer][state->deckCount[nextPlayer]--] = -1;
            state->deckCount[nextPlayer]--;
        }

        if (tributeRevealedCards[0] == tributeRevealedCards[1])
        {                       //If we have a duplicate card, just drop one 
            state->playedCards[state->playedCardCount] =
                tributeRevealedCards[1];
            state->playedCardCount++;
            tributeRevealedCards[1] = -1;
        }

        for (i = 0; i <= 2; i++)
        {
            if (tributeRevealedCards[i] == copper
                || tributeRevealedCards[i] == silver
                || tributeRevealedCards[i] == gold)
            {                   //Treasure cards
                *bonus += 2;
            }

            else if (tributeRevealedCards[i] == estate
                     || tributeRevealedCards[i] == duchy
                     || tributeRevealedCards[i] == province
                     || tributeRevealedCards[i] == gardens
                     || tributeRevealedCards[i] == great_hall)
            {                   //Victory Card Found
                drawCard(currentPlayer, state);
                drawCard(currentPlayer, state);
            }
            else
            {                   //Action Card
                state->numActions = state->numActions + 2;
            }
        }

        return 0;

    case ambassador:
        j = 0;                  //used to check if player has enough cards to discard

        if (choice2 > 2 || choice2 < 0)
        {
            return -1;
        }

        if (choice1 == handPos)
        {
            return -1;
        }

        for (i = 0; i < state->handCount[currentPlayer]; i++)
        {
            if (i != handPos && i == state->hand[currentPlayer][choice1]
                && i != choice1)
            {
                j++;
            }
        }
        if (j < choice2)
        {
            return -1;
        }

        dprintf ("Player %d reveals card number: %d\n", currentPlayer,
                 state->hand[currentPlayer][choice1]);

        //increase supply count for choosen card by amount being discarded
        state->supplyCount[state->hand[currentPlayer][choice1]] += choice2;

        //each other player gains a copy of revealed card
        for (i = 0; i < state->numPlayers; i++)
        {
            if (i != currentPlayer)
            {
                gainCard(state->hand[currentPlayer][choice1], state, 0, i);
            }
        }

        //discard played card from hand
        discardCard(handPos, currentPlayer, state, 0);

        //trash copies of cards returned to supply
        for (j = 0; j < choice2; j++)
        {
            for (i = 0; i < state->handCount[currentPlayer]; i++)
            {
                if (state->hand[currentPlayer][i] ==
                    state->hand[currentPlayer][choice1])
                {
                    discardCard(i, currentPlayer, state, 1);
                    break;
                }
            }
        }

        return 0;

    case cutpurse:

        *bonus += 2;
        
        for (i = 0; i < state->numPlayers; i++)
        {
            if (i != currentPlayer)
            {
                for (j = 0; j < state->handCount[i]; j++)
                {
                    if (state->hand[i][j] == copper)
                    {
                        discardCard(j, i, state, 0);
                        break;
                    }
                    if (j == state->handCount[i])
                    {
                        for (k = 0; k < state->handCount[i]; k++)
                            dprintf ("Player %d reveals card number %d\n",
                                     i, state->hand[i][k]);
                        break;
                    }
                }

            }

        }

        //discard played card from hand
        discardCard(handPos, currentPlayer, state, 0);

        return 0;


    case embargo:
        //+2 Coins
        *bonus += 2;

        //see if selected pile is in play
        if (state->supplyCount[choice1] == -1)
            return -1;
        
        //add embargo token to selected supply pile
        state->embargoTokens[choice1]++;

        //trash card
        discardCard(handPos, currentPlayer, state, 1);
        return 0;

    case outpost:
        //set outpost flag
        state->outpostPlayed++;

        //discard card
        discardCard(handPos, currentPlayer, state, 0);
        return 0;

    case salvager:
       return salvager_effect (state, currentPlayer, choice1, bonus);

    case sea_hag:
        return sea_hag_effect (state, currentPlayer);

    case treasure_map:
        //search hand for another treasure_map
        index = -1;
        for (i = 0; i < state->handCount[currentPlayer]; i++)
        {
            if (state->hand[currentPlayer][i] == treasure_map
                && i != handPos)
            {
                index = i;
                break;
            }
        }
        if (index > -1)
        {
            //trash both treasure cards
            discardCard(handPos, currentPlayer, state, 1);
            discardCard(index, currentPlayer, state, 1);

            //gain 4 Gold cards
            for (i = 0; i < 4; i++)
            {
                gainCard(gold, state, 1, currentPlayer);
            }

            //return success
            return 1;
        }
        //no second treasure_map found in hand
        return -1;
    }

    return -1;
}

int discardCard(int handPos, int currentPlayer, struct gameState *state,
                int trashFlag)
{

    //if card is not trashed, added to Played pile 
    if (trashFlag < 1)
    {
        if (currentPlayer == state->whoseTurn)
            //add card to played pile
            state->playedCards[state->playedCardCount++] =
                state->hand[currentPlayer][handPos];
        else
            //add directly to discard pile
            state->discard[currentPlayer][state->discardCount[currentPlayer]++] =
                state->hand[currentPlayer][handPos];
    }
    //set played card to -1
    state->hand[currentPlayer][handPos] = -1;

    //remove card from player's hand
    if (handPos == (state->handCount[currentPlayer] - 1))       //last card in hand array is played
    {
        //reduce number of cards in hand
        state->handCount[currentPlayer]--;
    }
    else if (state->handCount[currentPlayer] == 1)      //only one card in hand
    {
        //reduce number of cards in hand
        state->handCount[currentPlayer]--;
    }
    else
    {
        //replace discarded card with last card in hand
        state->hand[currentPlayer][handPos] =
            state->hand[currentPlayer][(state->handCount[currentPlayer] -
                                        1)];
        //set last card to -1
        state->hand[currentPlayer][state->handCount[currentPlayer] - 1] =
            -1;
        //reduce number of cards in hand
        state->handCount[currentPlayer]--;
    }

    return 0;
}

int gainCard(int supplyPos, struct gameState *state, int toFlag,
             int player)
{
    //Note: supplyPos is enum of choosen card

    //check if supply pile is empty (0) or card is not used in game (-1)
    if (supplyCount(supplyPos, state) < 1)
    {
        return -1;
    }
    //added card for [whoseTurn] current player:
    // toFlag = 0 : add to discard
    // toFlag = 1 : add to deck
    // toFlag = 2 : add to hand

    if (toFlag == 1)
    {
        state->deck[player][state->deckCount[player]] = supplyPos;
        state->deckCount[player]++;
    }
    else if (toFlag == 2)
    {
        state->hand[player][state->handCount[player]] = supplyPos;
        state->handCount[player]++;
    }
    else
    {
        state->discard[player][state->discardCount[player]] = supplyPos;
        state->discardCount[player]++;
    }

    //decrease number in supply pile
    state->supplyCount[supplyPos]--;

    return 0;
}

// updateCoins still takes a bonus argument instead of looking in state->bonus
// because we want to maintain compatiblity with other test suites that other
// people may have written, and that means not changing the number of
// arguments or what they do.
int updateCoins(int player, struct gameState *state, int bonus)
{
    int i;

    //reset coin count
    state->coins = 0;

    //add coins for each Treasure card in player's hand
    for (i = 0; i < state->handCount[player]; i++)
    {
        if (state->hand[player][i] == copper)
        {
            state->coins += 1;
        }
        else if (state->hand[player][i] == silver)
        {
            state->coins += 2;
        }
        else if (state->hand[player][i] == gold)
        {
            state->coins += 3;
        }
    }

    //add bonus
    state->coins += bonus;

    return 0;
}


//end of dominion.c
